import { LazyList, LazyNumber } from "./types"
import { repeat, map, cons } from "./common";
import {  round, log2 } from "./number"

const elimError =
    (m: LazyNumber) =>
        (lsx: LazyList<number>): LazyList<number> => {
            const xs = lsx();
            if (xs === null) {
                return () => null;
            }
            const a = xs.head()
            const ys = xs.tail()
            if (ys === null) {
                return () => null;
            }
            const b = ys.head();
            return cons
                (() => (b * (Math.pow(2, m()) - a) / (Math.pow(2, m()) - 1)))
                (() => elimError(m)(xs.tail)())
        }

const order = (lxs: LazyList<number>): LazyNumber => {
    const xs = lxs();
    if (xs === null) {
        console.log("invalid input for func `order`")
        return () => 0
    }
    const a = xs.head();
    const ys = xs.tail();
    if (ys === null) {
        console.log("invalid input for func `order`");
        return () => 0;
    }
    const b = ys.head();
    const zs = ys.tail();
    if (zs === null) {
        console.log("invalid input for func `order`");
        return () => 0;
    }
    const c = zs.head();

    return round(
        log2(
            () => ((a - c) / (b - c) - 1)
        )
    )
}

export const improve =
    (lxs: LazyList<number>): LazyList<number> =>
        elimError(order(lxs))(lxs)



const second = (xs: LazyList<number>): LazyNumber => {
    const pair = xs();
    if (pair === null) {
        console.log("invalid input for func `second`");
        return () => 0;
    }
    const tail = pair.tail();
    if (tail === null) {
        console.log("invalid input for func `second`");
        return () => 0;
    }
    return tail.head;
}

export const superr = (xs: LazyList<number>) => {
    return map(second)(repeat(improve)(xs))
}